package com.gxar.quick.ar.server.base.model.protocol.client.wechat_mp;

import com.gxar.common.exception.APIRuntimeException;
import com.gxar.common.utils.AssertUtils;
import com.gxar.common.utils.StringUtils;
import com.gxar.quick.ar.server.base.common.enums.protocol.*;
import com.gxar.quick.ar.server.base.model.ResultCodeEnum;
import com.gxar.quick.ar.server.base.model.protocol.ArQuaternion;
import com.gxar.quick.ar.server.base.model.protocol.ArVector3;
import com.gxar.quick.ar.server.base.model.protocol.common.CommonArContentModel;
import com.gxar.quick.ar.server.base.model.protocol.common.CommonArItemBorderModel;
import com.gxar.quick.ar.server.base.model.protocol.common.CommonArProtocol;
import lombok.Data;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 微信小程序 - AR内容信息
 *
 * @author zxh
 * @version 1.0
 * @created 2024/01/02.
 */
@Data
public class WechatMpClientArContentModel {

    /**
     * 元素编号
     */
    private String id;

    /**
     * 作品编号
     */
    private String workId;

    /**
     * 内容类型
     */
    private String type;

    /**
     * 子类型
     */
    private String subType;

    /**
     * 链接类型
     */
    private String linkType;

    /**
     * 处理类型(客户端渲染方式)
     */
    private String processType;

    /**
     * 资源链接
     */
    private String src;

    /**
     * 位移
     */
    private String position;

    /**
     * 旋转角，欧拉角，XYZ
     */
    private String rotation;

    /**
     * 放缩
     */
    private String scale;

    /**
     * 填充类型
     */
    private String fillType;

    /**
     * 是否边框
     */
    private Boolean isBorder;

    /**
     * 是否存在边框
     */
    private Boolean hasBorder;

    /**
     * 边框信息
     */
    private WechatMpClientArItemBorderModel border;

    private String alphaMode;

    /**
     * 特效
     */
    private String effect;

    /**
     * 文本配置
     */
    private WechatMpClientArItemTextModel textItem;

    /**
     * 动画效果
     */
    private WechatMpClientArItemAnimationModel animation;

    /**
     * 是否存在四元数
     */
    private Boolean hasQuaternion;

    /**
     * 四元数
     */
    private ArQuaternion quaternion;

    /**
     * 原始四元数
     */
    private ArQuaternion originQuaternion;

    public static List<WechatMpClientArContentModel> from(CommonArProtocol inputProtocol) {
        List<CommonArContentModel> inputModels = inputProtocol.getContentModelList();

        List<WechatMpClientArContentModel> commonModels = inputModels.stream()
                .filter(Objects::nonNull)
                .map((inputModel) -> constructCommonContent(inputProtocol, inputModel))
                .collect(Collectors.toList());
        List<WechatMpClientArContentModel> borderModels = inputModels.stream()
                .filter(CommonArContentModel::getHasBorder)
                .map((inputModel) -> constructUnifiedBorderContent(inputProtocol, inputModel))
                .collect(Collectors.toList());

        List<WechatMpClientArContentModel> outputModels = new ArrayList<>(commonModels.size() + borderModels.size());
        outputModels.addAll(commonModels);
        outputModels.addAll(borderModels); // 边框作为一般内容导入

        return outputModels;
    }

    private static WechatMpClientArContentModel constructCommonContent(CommonArProtocol inputProtocol, CommonArContentModel inputModel) {
        WechatMpClientArContentModel outputModel = new WechatMpClientArContentModel();

        outputModel.setId(inputModel.getId());
        outputModel.setWorkId(inputProtocol.getWorkId());
        outputModel.setType(inputModel.getType());
        outputModel.setSubType(inputModel.getSubType().getName());
        if (Objects.nonNull(inputModel.getLinkType())) {
            outputModel.setLinkType(inputModel.getLinkType().getName());
        }
        outputModel.setSrc(inputModel.getEncodeLinkUrl());
        outputModel.setRotation(inputModel.getRotation().toString());

        if (Objects.nonNull(inputModel.getFillType())) {
            outputModel.setFillType(inputModel.getFillType().getName());
        } else {
            // 编辑器协议中未提供填充类型, 给予默认值
            outputModel.setFillType(ArContentFillTypeEnum.AUTO.getName());
        }

        outputModel.setAlphaMode(inputModel.getAlphaMode());
        outputModel.setEffect(inputModel.getEffect().getName());
        outputModel.setTextItem(WechatMpClientArItemTextModel.from(inputModel.getText()));
        outputModel.setAnimation(WechatMpClientArItemAnimationModel.from(inputModel.getAnimation()));
        outputModel.setHasQuaternion(Objects.nonNull(inputModel.getQuaternion()));
        outputModel.setQuaternion(inputModel.getQuaternion());
        outputModel.setOriginQuaternion(inputModel.getOriginQuaternion());

        if (ArDisplayModeEnum.PLANE.equals(inputProtocol.getDisplayMode())) {
            // 投放模式, 缩小展示
            ArVector3 planeModeScale = WechatMpClientArProtocol.getSizeOnPlaneMode(inputModel.getScale());
            outputModel.setScale(planeModeScale.toString());

            ArVector3 planeModePosition = WechatMpClientArProtocol.getSizeOnPlaneMode(inputModel.getPosition());
            outputModel.setPosition(planeModePosition.toString());
        } else {
            outputModel.setPosition(inputModel.getPosition().toString());
            outputModel.setScale(inputModel.getScale().toString());
        }

        outputModel.setIsBorder(inputModel.getIsBorder());
        if (Objects.nonNull(inputModel.getBorder())) {
            outputModel.setHasBorder(true);
            outputModel.setBorder(WechatMpClientArItemBorderModel.from(inputModel.getBorder()));
        } else {
            outputModel.setHasBorder(false);
        }

        if (ArProtocolEditorEnum.WEB_EDITOR.equals(inputProtocol.getEditor())) {
            outputModel.updateProcessType(inputProtocol.getProductMethod());
        }

        return outputModel;
    }

    private static WechatMpClientArContentModel constructUnifiedBorderContent(CommonArProtocol inputProtocol, CommonArContentModel inputModel) {
        WechatMpClientArContentModel outputModel = new WechatMpClientArContentModel();

        CommonArItemBorderModel borderModel = inputModel.getBorder();
        AssertUtils.notNull(borderModel, ResultCodeEnum.CONVERT_PROTOCOL_PARAM_ERROR);

        outputModel.setId(borderModel.getId());
        outputModel.setWorkId(inputProtocol.getWorkId());
        outputModel.setType(borderModel.getType());
        outputModel.setSubType(borderModel.getSubType().getName());
        outputModel.setHasBorder(false); // 没有边框套边框

        if (Objects.nonNull(borderModel.getLinkType())) {
            outputModel.setLinkType(borderModel.getLinkType().getName());
        } else {
            ArMediaTypeEnum linkType = parseTypeFromLinkUrl(borderModel.getLinkUrl());
            if (Objects.nonNull(linkType)) {
                outputModel.setLinkType(linkType.getName());
            }
        }

        outputModel.setSrc(borderModel.getEncodeLinkUrl());
        outputModel.setRotation(borderModel.getRotation().toString());

        if (Objects.nonNull(borderModel.getFillType())) {
            outputModel.setFillType(borderModel.getFillType().getName());
        } else {
            // 编辑器协议未提供, 给予默认值
            outputModel.setFillType(ArContentFillTypeEnum.AUTO.getName());
        }

        outputModel.setIsBorder(borderModel.getIsBorder());
        outputModel.setAlphaMode(borderModel.getAlphaMode());
        outputModel.setEffect(borderModel.getEffect().getName());
        outputModel.setTextItem(WechatMpClientArItemTextModel.from(inputModel.getText()));
        outputModel.setAnimation(WechatMpClientArItemAnimationModel.from(inputModel.getAnimation()));
        outputModel.setHasQuaternion(Objects.nonNull(inputModel.getQuaternion()));
        outputModel.setQuaternion(inputModel.getQuaternion());
        outputModel.setOriginQuaternion(inputModel.getOriginQuaternion());

        if (ArDisplayModeEnum.PLANE.equals(inputProtocol.getDisplayMode())) {
            // 投放模式, 缩小展示
            ArVector3 planeModeScale = WechatMpClientArProtocol.getSizeOnPlaneMode(borderModel.getScale());
            outputModel.setScale(planeModeScale.toString());

            ArVector3 planeModePosition = WechatMpClientArProtocol.getSizeOnPlaneMode(borderModel.getPosition());
            outputModel.setPosition(planeModePosition.toString());
        } else {
            outputModel.setPosition(borderModel.getPosition().toString());
            outputModel.setScale(borderModel.getScale().toString());
        }

        if (ArProtocolEditorEnum.WEB_EDITOR.equals(inputProtocol.getEditor())) {
            outputModel.updateProcessType(inputProtocol.getProductMethod());
        }

        return outputModel;
    }

    private void updateProcessType(ArProductMethodEnum productMethod) {
        if (ArWebEditorContentTypeEnum.GLTF.getName().equals(this.type)) {
            this.processType = WechatMpClientArProtocol.CLIENT_PROCESS_TYPE_GLTF;
        } else if (ArWebEditorContentTypeEnum.TEXT_BOX.getName().equals(this.type)) {
            // 文本框
            if (ArMediaTypeEnum.VIDEO.getName().equals(this.linkType)) {
                // 视频文本框
                this.processType = WechatMpClientArProtocol.CLIENT_PROCESS_TYPE_VIDEO;
                this.effect = ArEffectEnum.TRANSPARENT_VIDEO.getName(); // 需要镂空效果
            } else if (ArMediaTypeEnum.IMAGE.getName().equals(this.linkType)) {
                // 图片文本框
                this.processType = WechatMpClientArProtocol.CLIENT_PROCESS_TYPE_IMAGE;

                if (ArContentSubTypeEnum.SPRITE.getName().equals(this.subType)) {
                    this.effect = ArEffectEnum.PLAY_FRAMES.getName(); // 序列帧播放
                } else if (ArContentSubTypeEnum.STATIC.getName().equals(this.subType)) {
                    this.alphaMode = ArAlphaMode.BLEND.getName();
                } else {
                    throw new APIRuntimeException(ResultCodeEnum.CONVERT_PROTOCOL_PARAM_ERROR);
                }
            } else {
                throw new APIRuntimeException(ResultCodeEnum.CONVERT_PROTOCOL_PARAM_ERROR);
            }
        } else if (ArWebEditorContentTypeEnum.VIDEO_BOX.getName().equals(this.type)) {
            // 视频框
            this.processType = WechatMpClientArProtocol.CLIENT_PROCESS_TYPE_VIDEO;
        } else if (ArWebEditorContentTypeEnum.WORD_ART.getName().equals(this.type)) {
            // 艺术字
            this.processType = WechatMpClientArProtocol.CLIENT_PROCESS_TYPE_IMAGE;
            this.alphaMode = ArAlphaMode.BLEND.getName();
        } else if (ArWebEditorContentTypeEnum.IMAGE.getName().equals(this.type)) {
            // 图片

            if (ArMediaTypeEnum.IMAGE.getName().equals(this.linkType)) {
                // 静态图片
                this.processType = WechatMpClientArProtocol.CLIENT_PROCESS_TYPE_IMAGE;
                if (ArContentSubTypeEnum.SPRITE.getName().equals(this.subType)) {
                    this.effect = ArEffectEnum.PLAY_FRAMES.getName(); // 序列帧播放
                }
            } else if (ArMediaTypeEnum.VIDEO.getName().equals(this.linkType)) {
                // 动态图片
                this.processType = WechatMpClientArProtocol.CLIENT_PROCESS_TYPE_VIDEO;

                if (ArProductMethodEnum.ADVANCED.equals(productMethod)) {
                    // 仅进阶制作的动态图需要, 简易制作视频不需要镂空效果?
//                        this.effect = ArEffectEnum.TRANSPARENT_VIDEO.getName();
                }
            } else {
                throw new APIRuntimeException(ResultCodeEnum.CONVERT_PROTOCOL_PARAM_ERROR);
            }
        } else {
            throw new APIRuntimeException(ResultCodeEnum.CONVERT_PROTOCOL_PARAM_ERROR);
        }
    }

    // TODO: 兜底使用, 后期移除
    private static ArMediaTypeEnum parseTypeFromLinkUrl(String linkUrl) {
        if (StringUtils.isEmpty(linkUrl)) {
            return null;
        }

        String urlLower = linkUrl.toLowerCase();
        if (urlLower.endsWith("gltf") || urlLower.endsWith("glb")) {
            return ArMediaTypeEnum.GLTF;
        } else if (urlLower.endsWith("mp4")) {
            return ArMediaTypeEnum.VIDEO;
        } else if (urlLower.endsWith("mp3")) {
            return ArMediaTypeEnum.MUSIC;
        } else {
            return ArMediaTypeEnum.IMAGE;
        }
    }
}
